单个参数的传递
通过#{参数名}取出参数值,实际上在传递单个参数的时候,MyBatis不会做特殊处理,实际上#{}内部的参数名你可以任意取值,但还是建议和接口中参数的名字保持一致。
多个参数的传递
MyBatis遇见多个参数时会进行特殊处理,多个参数会被封装成一个Map,#{}就是从Map中获取指定key的值,key的值为param1...paramN,而value才是我们传入的值。要想从传入的Map中取值,只能通过#{param1}、#{param2}…或者#{0}、#{1}…
|
|
其对应的SQL映射为:
|
|
然后进行测试:
|
|
这种方法虽然可以使用,但是不够直观,因此,通常使用命名参数:明确指定封装参数时Map的key,不要再使用param1、param2...,可以使用@Param注解来完成。
|
|
这样,在封装Map时所使用的key就是id和lastName。
另一方面,如果参数很多,正好是业务逻辑的数据模型,我们就可以直接传入POJO,此时使用#{属性名}就可以取出传入的POJO属性值。
如果多个参数不是业务逻辑的数据模型,没有对应的POJO,为了方便,我们也可以传入Map,此时#{key}就是取出Map中对应的值。
|
|
|
|
|
|
如果多个参数不是业务模型中的数据,但是经常要使用,推荐编写一个TO(Transfer Object)数据传输对象。比如分页查询的时候封装一个Page:
|
|
需要注意的是,如果接口参数类型为Collection(List、Set)类型或者是数组也会特殊处理,也是把传入的List或者数组封装在Map中,若为Collection,key使用的是collection,若为List,key还可以使用list;若为数组,则key使用的是array,例如:
假设接口如下:
|
|
则取值的时候取出第一个id的值需要使用#{list[0]}。
参数值的获取
#{}可以获取Map中的值或者POJO对象属性的值,对于MyBatis来说,还支持${}的取值方式。两者的区别在于:#{}是以预编译的形式将参数设置到SQL语句中,可以防止SQL注入,而${}取出的值直接拼装在SQL语句中,会有安全问题。
大多情况下我们取参数的值都应该使用#{},对于原生JDBC不支持占位符的地方就可以使用${}进行取值。举个例子:
分表操作,按照年份分表拆分:
|
|
原生JDBC是不能如下操作的:
|
|
此时可以使用${}进行取值。
再比如排序:
|
|
同样地,原生JDBC不支持order by后面使用占位符。
参数处理
参数可以指定一个特殊的数据类型:
12#{property, javaType=int, jdbcType=NUMERIC}#{height, javaType=double, jdbcType=NUMERIC, numericScale=2}javaType通常可以从参数对象中来确定- 如果
null被当做值来传递,对于所有可能为空的列,jdbcType需要被设置 - 对于数值类型,还可以设置小数点后保留的位数
mode属性(存储过程)允许指定IN、OUT或INOUT参数,如果参数为OUT或INOUT,参数对象属性的真实值将会被改变
jdbcType通常需要在某种特定的条件下被设置:在我们数据为null的时候,有些数据库可能不能识别MyBatis对null的默认处理比如Oracle,Oracle会报JdbcType OTHER无效的类型错误。MyBatis对所有的null映射的是原生Jdbc的OTHER类型,Oracle不能正确处理。此时可以做如下设置:
1#{email, jdbcType=NULL}这是因为全局配置中
jdbcTypeForNull=OTHER,Oracle不支持,因此主要有以下两种解决办法:#{email, jdbcType=OTHER}这种解决方法只会影响当前
SQL语句的jdbcType。更改全局配置中
jdbcTypeForNull,将其改为NULL即可,如下:123<settings><setting name="jdbcTypeForNull" value="NULL"/></settings>